﻿using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Framework;
using Umbraco.Framework.Context;
using Umbraco.Framework.Persistence.Model;
using Umbraco.Framework.Persistence.Model.Associations;
using Umbraco.Framework.Persistence.Model.Associations._Revised;
using Umbraco.Framework.Persistence.Model.Attribution.MetaData;
using Umbraco.Framework.Persistence.Model.Constants;
using Umbraco.Framework.Persistence.ProviderSupport._Revised;
using Umbraco.Hive.ProviderSupport;
using Umbraco.Hive.Providers.WordPress.Schema.Model;

namespace Umbraco.Hive.Providers.WordPress.Schema
{
    public class Repository : AbstractSchemaRepository
    {
        public Repository(ProviderMetadata providerMetadata, IFrameworkContext frameworkContext) 
            : base(providerMetadata, frameworkContext)
        { }

        #region Properties

        /// <summary>
        /// Gets a value indicating whether this instance can read relations.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance can read relations; otherwise, <c>false</c>.
        /// </value>
        public override bool CanReadRelations { get { return true; } }

        /// <summary>
        /// Gets a value indicating whether this instance can write relations.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance can write relations; otherwise, <c>false</c>.
        /// </value>
        public override bool CanWriteRelations { get { return false; } }
        
        #endregion

        #region Schema

        /// <summary>
        /// Identifies if a <see cref="!:TEntity"/> with matching <paramref name="id"/> can be found in this repository.
        /// </summary>
        /// <typeparam name="TEntity">The type of the entity.</typeparam>
        /// <param name="id">The id.</param>
        /// <returns>
        ///   <code>
        /// true
        /// </code>
        /// if the item with <paramref name="id"/> can be found, otherwise
        /// <code>
        /// false
        /// </code>
        /// .
        /// </returns>
        public override bool Exists<TEntity>(HiveId id)
        {
            return Get<TEntity>(true, id).Any();
        }

        /// <summary>
        /// Performs the add or update.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public override void PerformAddOrUpdate(AbstractSchemaPart entity)
        {
            return;
        }

        /// <summary>
        /// Deletes the specified id.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id">The id.</param>
        public override void Delete<T>(HiveId id)
        {
            return;
        }

        /// <summary>
        /// Performs the get.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="allOrNothing">if set to <c>true</c> [all or nothing].</param>
        /// <param name="ids">The ids.</param>
        /// <returns></returns>
        protected override IEnumerable<T> PerformGet<T>(bool allOrNothing, params HiveId[] ids)
        {
            foreach (var hiveId in ids.Where(x => x.Value.Type == HiveIdValueTypes.Int32).Select(x => (int)x.Value))
            {
                if (hiveId == 1)
                    yield return new PostSchema() as T;
                else if (hiveId == 2)
                    yield return new CategorySchema() as T;
            }
        }

        /// <summary>
        /// Performs the get all.
        /// </summary>
        /// <typeparam name="TEntity">The type of the entity.</typeparam>
        /// <returns></returns>
        public override IEnumerable<TEntity> PerformGetAll<TEntity>()
        {
            yield return new PostSchema() as TEntity;
            yield return new CategorySchema() as TEntity;
        }
        
        #endregion

        #region Relations

        /// <summary>
        /// Adds the relation.
        /// </summary>
        /// <param name="item">The item.</param>
        public override void AddRelation(IReadonlyRelation<IRelatableEntity, IRelatableEntity> item)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Removes the relation.
        /// </summary>
        /// <param name="item">The item.</param>
        public override void RemoveRelation(IRelationById item)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Performs the get parent relations.
        /// </summary>
        /// <param name="childId">The child id.</param>
        /// <param name="relationType">Type of the relation.</param>
        /// <returns></returns>
        public override IEnumerable<IRelationById> PerformGetParentRelations(HiveId childId, RelationType relationType = null)
        {
            if (childId.EqualsIgnoringProviderId(FixedHiveIds.ContentRootSchema)) yield break;
            yield return new RelationById(FixedHiveIds.ContentRootSchema, childId, FixedRelationTypes.SchemaTreeRelationType, 0);
        }

        /// <summary>
        /// Performs the get child relations.
        /// </summary>
        /// <param name="parentId">The parent id.</param>
        /// <param name="relationType">Type of the relation.</param>
        /// <returns></returns>
        public override IEnumerable<IRelationById> PerformGetChildRelations(HiveId parentId, RelationType relationType = null)
        {
            if (parentId == FixedHiveIds.ContentRootSchema)
            {
                foreach (var entity in GetAll<EntitySchema>())
                {
                    yield return new RelationById(parentId, entity.Id, FixedRelationTypes.SchemaTreeRelationType, 0);
                }
            }
        }

        /// <summary>
        /// Performs the get ancestor relations.
        /// </summary>
        /// <param name="descendentId">The descendent id.</param>
        /// <param name="relationType">Type of the relation.</param>
        /// <returns></returns>
        public override IEnumerable<IRelationById> PerformGetAncestorRelations(HiveId descendentId, RelationType relationType = null)
        {
            return GetParentRelations(descendentId, relationType).SelectRecursive(x => GetParentRelations(x.SourceId, relationType));
        }

        /// <summary>
        /// Performs the get descendent relations.
        /// </summary>
        /// <param name="ancestorId">The ancestor id.</param>
        /// <param name="relationType">Type of the relation.</param>
        /// <returns></returns>
        public override IEnumerable<IRelationById> PerformGetDescendentRelations(HiveId ancestorId, RelationType relationType = null)
        {
            return GetChildRelations(ancestorId, relationType).SelectRecursive(x => GetChildRelations(x.DestinationId, relationType));
        }

        /// <summary>
        /// Performs the find relation.
        /// </summary>
        /// <param name="sourceId">The source id.</param>
        /// <param name="destinationId">The destination id.</param>
        /// <param name="relationType">Type of the relation.</param>
        /// <returns></returns>
        public override IRelationById PerformFindRelation(HiveId sourceId, HiveId destinationId, RelationType relationType)
        {
            throw new NotImplementedException();
        }

        #endregion

        /// <summary>
        /// Handles the disposal of resources. Derived from abstract class <see cref="DisposableObject"/> which handles common required locking logic.
        /// </summary>
        protected override void DisposeResources()
        {
            return;
        }
    }
}
